package com.example.design.singleton;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * @ClassName Singleton11
 * @Description 使用读写锁
 * @Author Administrator
 * @Date 2020/5/7 13:14
 * @Version 1.0
 */
public class Singleton11 {

    private Singleton11(){}

    // 维护注册信息的map
    private static Map<String, Object> map = new HashMap<>();
    // 多线程的可重入的读写锁
    private static final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
    // 可读锁,可以多个只读锁并存，锁定时可写锁不可用
    private static final Lock rLock = rwLock.readLock();
    // 可写锁，只能有一个，锁定时其它锁不可用
    private static final Lock wLock = rwLock.writeLock();

    public static Object getInstance(String className) throws InstantiationException, IllegalAccessException,
            ClassNotFoundException {
        Object instance = null;
        // 锁定读取锁
        rLock.lock();
        instance = map.get(className);
        try {
            if (instance != null) {
                return instance;
            }
        } finally {
            // 释放读取锁
            rLock.unlock();
        }

        // 锁定写入的锁
        wLock.lock();
        try {
            instance = map.get(className);
            if (instance != null) {
                return instance;
            }

            // 使用反射方式实例化单例对象
            instance = Class.forName(className).newInstance();
            // 放入map中存储
            map.put(className, instance);

        } finally {
            wLock.unlock();
        }
        return instance;
    }

    private String name;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }

    public static void main(String[] args) throws IllegalAccessException, ClassNotFoundException, InstantiationException {
        Singleton11 s1 = (Singleton11) Singleton11.getInstance("com.example.design.singleton.Singleton11");
        Singleton11 s2 = (Singleton11) Singleton11.getInstance("com.example.design.singleton.Singleton11");
        s1.setName("zhangsan11");
        s2.setName("lisi11");
        System.out.println(s1.getName());
        System.out.println(s2.getName());
        System.out.println(s1.getName().equals(s2.getName()));
    }

}
